[アップデート] Amazon S3 デフォルトのデータ整合性保護が変わります #AWSreinvent

[アップデート] Amazon S3 デフォルトのデータ整合性保護が変わります #AWSreinvent

マルチパートアップロード時やSSE-KMSで暗号化した時のデータ整合性チェックが楽になる
Clock Icon2024.12.09

S3バケットに到達する前にオブジェクトの改竄検出方法が気になる

こんにちは、のんピ(@non____97)です。

皆さんはS3バケットを利用していて、S3バケットに到達する前にオブジェクトの改竄検出方法が気になったことはありますか? 私はあります。

S3バケットではデフォルトでMD5チェックサムとETagを組み合わせることによってデータ整合性の検証が行われます。

ただし、以下のシチュエーションにおいては事前計算されるMD5チェックサムとETagの値が異なっていました。

  • オブジェクトが PutObject、PostObject、または CopyObject オペレーションによって、または AWS Management Console を介して作成され、そのオブジェクトがSSE-C または SSE-KMS によって暗号化されている場合
  • オブジェクトがマルチパートアップロードのプロセスまたは UploadPartCopy オペレーションによって作成された場合

参考 : オブジェクトの整合性をチェックする - Amazon Simple Storage Service

そのため、通常のオブジェクト追加操作では整合性がとれているのか確認をすることができません。

上述のようなシチュエーションでも整合性チェックを行いたい場合は、PUT時に自前でチェックサムを計算した上でメタデータを付与し、GET時にメタデータのチェックサムとGETしたオブジェクトから生成したチェックサムと比較をする必要があります。

マルチパートのパーツとして Amazon S3 にアップロードするようなオブジェクトの ETag 形式は、従来の PUT 要求を使用してアップロードするオブジェクトの ETag 形式とは異なります。ソースファイルの MD5 チェックサム値を基準として保存するには、チェックサム値を含んだファイルを、カスタムメタデータとしてアップロードします。MD5 チェックサム値をカスタムメタデータとして追加するには、アップロードコマンドにオプションのパラメータ --metadata md5="examplemd5value1234/4Q" を追加します。

aws s3 cp large_test_file s3://DOC-EXAMPLE-BUCKET/ --metadata md5="examplemd5value1234/4Q"

Amazon S3 へのマルチパートアップロードに AWS CLI を使用 | AWS re:Post

今回アップデートによりデータ整合性の保護が強化されました。

具体的には以下のようなアップデートが行われています。

  • CLIやSDK、マネジメントコンソールからオブジェクトのPUT操作をしたときのデフォルトのチェックサムがMD5からCRC-64NVME
  • CLIやSDK、REST APIでチェックサム計算を行わないようにしたとしても、S3が自動的にCRC-64NVMEによるチェックサム計算を行うようになる
  • チェックサムの結果はETagだけではなく、S3オブジェクトメタデータに設定される
  • 追加チェックサムアルゴリズムにCRC-64NVMEが追加された

https://aws.amazon.com/about-aws/whats-new/2024/12/amazon-s3-default-data-integrity-protections/

AWS Blogsにも投稿されていますね。

https://aws.amazon.com/blogs/aws/introducing-default-data-integrity-protections-for-new-objects-in-amazon-s3/

今後数週間ですべての AWS リージョンに展開されるとのことですが、2024/12/9時点ではどうでしょう。

実際に試してみました。

チェックサムの計算方法

今回のアップデートによってマルチパートアップロード時のチェックサムの計算方法について、「フルオブジェクトチェックサム」と「複合チェックサムタイプ」と名前が付きました。

それぞれの意味は以下のとおりです。

チェックサムの計算方法 説明
フルオブジェクトチェックサム マルチパートアップロードの全パートから計算する
複合チェックサム マルチパートアップロードの個別パートのチェックサムを結合して計算する

「フルオブジェクトチェックサム」と「複合チェックサムタイプ」かで使用可能なチェックサムアルゴリズムは以下のように異なります。

チェックサムアルゴリズム フルオブジェクトチェックサム 複合チェックサム
CRC-64NVME 不可
CRC-32
CRC-32C
SHA-1 不可
SHA-256 不可

どちらのチェックサム計算方法で計算するかはCreateMultiPartUploadで指定可能です。また、オブジェクトのx-amz-checksum-typeメタデータを確認すれば、どちらのチェックサム計算方法で計算されたチェックサムなのか確認することも確認できます。

AWSとしてはCRC-64NVMEが推奨とのことです。フルオブジェクトチェックサムの方がリクエストを並列化でき、パフォーマンス的にメリットがあるようです。

For full object checksums, you can use CRC-64NVME, CRC-32, or CRC-32C checksum algorithms in S3. Full object checksums in multipart uploads are only available for CRC-based checksums because they can linearize into a full object checksum. This linearization allows Amazon S3 to parallelize your requests for improved performance. In particular, S3 can compute the checksum of the whole object from the part-level checksums. This type of validation isn’t available for other algorithms, such as SHA and MD5. Because S3 has default integrity protections, if objects are uploaded without a checksum, S3 automatically attaches the recommended full object CRC-64NVME checksum algorithm to the object.

Checking object integrity in Amazon S3 - Amazon Simple Storage Service

やってみた

過去マネジメントコンソールからS3バケットにPUTしたオブジェクトのETagとメタデータと、手元のファイルのMD5の計算結果を見てみましょう。

> aws s3api head-object --bucket datasync-s3-to-fsxn-test --key tier1A/images/1.AWSのサービスの場合.png
{
    "AcceptRanges": "bytes",
    "LastModified": "2024-12-02T00:32:03+00:00",
    "ContentLength": 162709,
    "ETag": "\"5a97286b9ea17df5a9853baf0da29944\"",
    "ContentType": "binary/octet-stream",
    "ServerSideEncryption": "AES256",
    "Metadata": {}
}

> md5sum ./images/1.AWSのサービスの場合.png
5a97286b9ea17df5a9853baf0da29944  ./1.AWSのサービスの場合.png

ETagとMD5の計算結果が一致していますね。

それでは新規にS3にオブジェクトをPUTした際にCRC-64NVMEによるチェックサムの計算が行われているか確認します。

使用しているAWS CLIのバージョンは2.22.8で、S3バケットはバージニア北部リージョンに存在します。

>  aws --version
aws-cli/2.22.8 Python/3.12.7 Darwin/24.1.0 source/arm64

AWS CLI v2のChange logを見たところ、AWS CLI側によるCRC-64NVMEによる自動チェックサム計算は行われるアップデートは適用されていないようです

https://raw.githubusercontent.com/aws/aws-cli/v2/CHANGELOG.rst

試していましょう。

> echo test > test.txt

> aws s3api put-object --bucket datasync-s3-to-fsxn-test --key tier1A/test/test.txt --debug
2024-12-05 11:24:29,231 - MainThread - awscli.clidriver - DEBUG - CLI version: aws-cli/2.22.8 Python/3.12.7 Darwin/24.1.0 source/arm64
2024-12-05 11:24:29,231 - MainThread - awscli.clidriver - DEBUG - Arguments entered to CLI: ['s3api', 'put-object', '--bucket', 'datasync-s3-to-fsxn-test', '--key', 'tier1A/test/test.txt', '--debug']
.
.
(中略)
.
.
2024-12-05 11:24:29,311 - MainThread - awscli.clidriver - DEBUG - OrderedDict({'acl': <awscli.arguments.CLIArgument object at 0x106b0dd60>, 'body': <awscli.arguments.CLIArgument object at 0x106b0dd90>, 'bucket': <awscli.arguments.CLIArgument object at 0x106b0ddf0>, 'cache-control': <awscli.arguments.CLIArgument object at 0x106b0de20>, 'content-disposition': <awscli.arguments.CLIArgument object at 0x106b0de50>, 'content-encoding': <awscli.arguments.CLIArgument object at 0x106b0de80>, 'content-language': <awscli.arguments.CLIArgument object at 0x106b0deb0>, 'content-length': <awscli.arguments.CLIArgument object at 0x106b0dee0>, 'content-md5': <awscli.arguments.CLIArgument object at 0x106b0df10>, 'content-type': <awscli.arguments.CLIArgument object at 0x106b0df40>, 'checksum-algorithm': <awscli.arguments.CLIArgument object at 0x106b0df70>, 'checksum-crc32': <awscli.arguments.CLIArgument object at 0x106b0dfd0>, 'checksum-crc32-c': <awscli.arguments.CLIArgument object at 0x106b0dfa0>, 'checksum-sha1': <awscli.arguments.CLIArgument object at 0x106b0e000>, 'checksum-sha256': <awscli.arguments.CLIArgument object at 0x106b0e030>, 'expires': <awscli.arguments.CLIArgument object at 0x106b0e090>, 'if-match': <awscli.arguments.CLIArgument object at 0x106b0e120>, 'if-none-match': <awscli.arguments.CLIArgument object at 0x106b0e150>, 'grant-full-control': <awscli.arguments.CLIArgument object at 0x106b0e0c0>, 'grant-read': <awscli.arguments.CLIArgument object at 0x106b0e0f0>, 'grant-read-acp': <awscli.arguments.CLIArgument object at 0x106b0e1b0>, 'grant-write-acp': <awscli.arguments.CLIArgument object at 0x106b0e1e0>, 'key': <awscli.arguments.CLIArgument object at 0x106b0e240>, 'write-offset-bytes': <awscli.arguments.CLIArgument object at 0x106b0e180>, 'metadata': <awscli.arguments.CLIArgument object at 0x106b0e270>, 'server-side-encryption': <awscli.arguments.CLIArgument object at 0x106b0e2a0>, 'storage-class': <awscli.arguments.CLIArgument object at 0x106b0e2d0>, 'website-redirect-location': <awscli.arguments.CLIArgument object at 0x106b0e330>, 'sse-customer-algorithm': <awscli.arguments.CLIArgument object at 0x106b0e360>, 'sse-customer-key': <awscli.arguments.CLIArgument object at 0x106b0e300>, 'sse-customer-key-md5': <awscli.arguments.CLIArgument object at 0x106b0e390>, 'ssekms-key-id': <awscli.arguments.CLIArgument object at 0x106b0e3c0>, 'ssekms-encryption-context': <awscli.arguments.CLIArgument object at 0x106b0e3f0>, 'bucket-key-enabled': <awscli.arguments.BooleanArgument object at 0x106b0e450>, 'no-bucket-key-enabled': <awscli.arguments.BooleanArgument object at 0x1040ebb60>, 'request-payer': <awscli.arguments.CLIArgument object at 0x106b0e420>, 'tagging': <awscli.arguments.CLIArgument object at 0x106b0e4e0>, 'object-lock-mode': <awscli.arguments.CLIArgument object at 0x106b0e480>, 'object-lock-retain-until-date': <awscli.arguments.CLIArgument object at 0x106b0e510>, 'object-lock-legal-hold-status': <awscli.arguments.CLIArgument object at 0x106b0e570>, 'expected-bucket-owner': <awscli.arguments.CLIArgument object at 0x106b0e5a0>})
.
.
(中略)
.
.
2024-12-05 11:24:29,324 - MainThread - botocore.hooks - DEBUG - Event load-cli-arg.s3.put-object.content-md5: calling handler <awscli.paramfile.URIArgumentHandler object at 0x105074fe0>
2024-12-05 11:24:29,324 - MainThread - botocore.hooks - DEBUG - Event load-cli-arg.s3.put-object.content-type: calling handler <awscli.paramfile.URIArgumentHandler object at 0x105074fe0>
2024-12-05 11:24:29,324 - MainThread - botocore.hooks - DEBUG - Event load-cli-arg.s3.put-object.checksum-algorithm: calling handler <awscli.paramfile.URIArgumentHandler object at 0x105074fe0>
2024-12-05 11:24:29,324 - MainThread - botocore.hooks - DEBUG - Event load-cli-arg.s3.put-object.checksum-crc32: calling handler <awscli.paramfile.URIArgumentHandler object at 0x105074fe0>
2024-12-05 11:24:29,324 - MainThread - botocore.hooks - DEBUG - Event load-cli-arg.s3.put-object.checksum-crc32-c: calling handler <awscli.paramfile.URIArgumentHandler object at 0x105074fe0>
2024-12-05 11:24:29,324 - MainThread - botocore.hooks - DEBUG - Event load-cli-arg.s3.put-object.checksum-sha1: calling handler <awscli.paramfile.URIArgumentHandler object at 0x105074fe0>
2024-12-05 11:24:29,324 - MainThread - botocore.hooks - DEBUG - Event load-cli-arg.s3.put-object.checksum-sha256: calling handler <awscli.paramfile.URIArgumentHandler object at 0x105074fe0>
2024-12-05 11:24:29,324 - MainThread - botocore.hooks - DEBUG - Event load-cli-arg.s3.put-object.expires: calling handler <awscli.paramfile.URIArgumentHandler object at 0x105074fe0>
2024-12-05 11:24:29,324 - MainThread - botocore.hooks - DEBUG - Event load-cli-arg.s3.put-object.if-match: calling handler <awscli.paramfile.URIArgumentHandler object at 0x105074fe0>
.
.
(中略)
.
.
2024-12-05 11:24:29,324 - MainThread - botocore.hooks - DEBUG - Event load-cli-arg.s3.put-object.sse-customer-key-md5: calling handler <awscli.paramfile.URIArgumentHandler object at 0x105074fe0>
.
.
(中略)
.
.
content-md5:1B2M2Y8AsgTpgAmY7PhCfg==
host:datasync-s3-to-fsxn-test.s3.us-east-1.amazonaws.com
.
.
(中略)
.
.
content-md5;host;x-amz-content-sha256;x-amz-date;x-amz-security-token
UNSIGNED-PAYLOAD
2024-12-05 11:24:29,354 - MainThread - botocore.auth - DEBUG - StringToSign:
AWS4-HMAC-SHA256
20241205T192429Z
20241205/us-east-1/s3/aws4_request
2fa1afff032f64945961ad6eacfa4876d80d7d18bd3ab7a37cbb3f9ac4ef1242
2024-12-05 11:24:29,354 - MainThread - botocore.auth - DEBUG - Signature:
2dd4771bc890215a531ea6ae5b16c23c33e4f7d5f0b58619530b9007b64332d5
2024-12-05 11:24:29,354 - MainThread - botocore.endpoint - DEBUG - Sending http request: <AWSPreparedRequest stream_output=False, method=PUT, url=https://datasync-s3-to-fsxn-test.s3.us-east-1.amazonaws.com/tier1A/test/test.txt, headers={'User-Agent': b'aws-cli/2.22.8 md/awscrt#0.22.0 ua/2.0 os/macos#24.1.0 md/arch#arm64 lang/python#3.12.7 md/pyimpl#CPython cfg/retry-mode#standard md/installer#source md/prompt#off md/command#s3api.put-object', 'Content-MD5': b'1B2M2Y8AsgTpgAmY7PhCfg==', 'X-Amz-Date': b'20241205T192429Z', 'X-Amz-Security-Token': b'<セキュリティトークン>', 'X-Amz-Content-SHA256': b'UNSIGNED-PAYLOAD', 'Authorization': b'AWS4-HMAC-SHA256 Credential=<一時アクセスきー>/20241205/us-east-1/s3/aws4_request, SignedHeaders=content-md5;host;x-amz-content-sha256;x-amz-date;x-amz-security-token, Signature=2dd4771bc890215a531ea6ae5b16c23c33e4f7d5f0b58619530b9007b64332d5', 'Content-Length': '0'}>
2024-12-05 11:24:29,354 - MainThread - botocore.httpsession - DEBUG - Certificate path: /opt/homebrew/Cellar/awscli/2.22.8/libexec/lib/python3.12/site-packages/awscli/botocore/cacert.pem
2024-12-05 11:24:29,354 - MainThread - urllib3.connectionpool - DEBUG - Starting new HTTPS connection (1): datasync-s3-to-fsxn-test.s3.us-east-1.amazonaws.com:443
2024-12-05 11:24:29,859 - MainThread - urllib3.connectionpool - DEBUG - https://datasync-s3-to-fsxn-test.s3.us-east-1.amazonaws.com:443 "PUT /tier1A/test/test.txt HTTP/1.1" 200 0
2024-12-05 11:24:29,861 - MainThread - botocore.hooks - DEBUG - Event before-parse.s3.PutObject: calling handler <function _handle_200_error at 0x1041c5620>
2024-12-05 11:24:29,861 - MainThread - botocore.hooks - DEBUG - Event before-parse.s3.PutObject: calling handler <function handle_expires_header at 0x1041c5440>
2024-12-05 11:24:29,862 - MainThread - botocore.parsers - DEBUG - Response headers: {'x-amz-id-2': 'jzMZh57W7FYqWASRNfFVA7PeN8U5yKoZhle69Wd1iKJH27gwdtKRdT7jITVpJdGmfz8xombYHKU=', 'x-amz-request-id': 'JX2T4AJPR68T77HA', 'Date': 'Thu, 05 Dec 2024 19:24:30 GMT', 'x-amz-server-side-encryption': 'AES256', 'ETag': '"d41d8cd98f00b204e9800998ecf8427e"', 'Content-Length': '0', 'Server': 'AmazonS3'}
2024-12-05 11:24:29,862 - MainThread - botocore.parsers - DEBUG - Response body:
b''
2024-12-05 11:24:29,886 - MainThread - botocore.hooks - DEBUG - Event needs-retry.s3.PutObject: calling handler <function _update_status_code at 0x1041c5760>
2024-12-05 11:24:29,886 - MainThread - botocore.hooks - DEBUG - Event needs-retry.s3.PutObject: calling handler <bound method RetryHandler.needs_retry of <botocore.retries.standard.RetryHandler object at 0x1072ce5a0>>
2024-12-05 11:24:29,886 - MainThread - botocore.retries.standard - DEBUG - Not retrying request.
2024-12-05 11:24:29,886 - MainThread - botocore.hooks - DEBUG - Event needs-retry.s3.PutObject: calling handler <bound method S3RegionRedirectorv2.redirect_from_error of <botocore.utils.S3RegionRedirectorv2 object at 0x1072ce330>>
2024-12-05 11:24:29,886 - MainThread - botocore.hooks - DEBUG - Event after-call.s3.PutObject: calling handler <function enhance_error_msg at 0x105f4eb60>
2024-12-05 11:24:29,886 - MainThread - botocore.hooks - DEBUG - Event after-call.s3.PutObject: calling handler <bound method RetryQuotaChecker.release_retry_quota of <botocore.retries.standard.RetryQuotaChecker object at 0x1072ce300>>
2024-12-05 11:24:29,886 - MainThread - awscli.formatter - DEBUG - RequestId: JX2T4AJPR68T77HA
{
    "ETag": "\"d41d8cd98f00b204e9800998ecf8427e\"",
    "ServerSideEncryption": "AES256"
}

>  aws s3api head-object --bucket datasync-s3-to-fsxn-test --key tier1A/test/test.txt
{
    "AcceptRanges": "bytes",
    "LastModified": "2024-12-09T07:11:14+00:00",
    "ContentLength": 0,
    "ETag": "\"d41d8cd98f00b204e9800998ecf8427e\"",
    "ContentType": "binary/octet-stream",
    "ServerSideEncryption": "AES256",
    "Metadata": {}
}

debugログを見ると、MD5によるチェックサムを計算した上でオブジェクトをPUTしていることが分かります。

一方で、アップデート時のCRC-64NVMEによるチェックサムの計算は2024/12/5時点でも行われていないようです。

CRC-64NVMEによるチェックサムの計算が行われた場合はx-amz-checksum-crc64nvmeと言うメタデータが設定されます。

首を長くして待ちましょう。

マルチパートアップロード時やSSE-KMSで暗号化した時のデータ整合性チェックが楽になる

Amazon S3 デフォルトでデータ整合性保護が変更になるアップデートを紹介しました。

これによりマルチパートアップロード時やSSE-KMSで暗号化した時のデータ整合性チェックが楽になります。

お手製の生合成チェックツールを用意していた人にとっては非常に嬉しいアップデートですね。

この記事が誰かの助けになれば幸いです。

以上、AWS事業本部 コンサルティング部の のんピ(@non____97)でした!

Share this article

facebook logohatena logotwitter logo

© Classmethod, Inc. All rights reserved.